package com.googlecode.shapeline.data.oswf;

import java.util.*;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.opensymphony.module.propertyset.*;
import com.opensymphony.util.Data;
import com.googlecode.shapeline.web.context.support.*;

public class IBatisPropertySet extends AbstractPropertySet {
	
	private final static org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(IBatisPropertySet.class.getName());
    protected String globalKey;
	protected SqlMapClient sqlMapClient;

    public void setSqlMapClient(SqlMapClient sqlMapClient) {
    	this.sqlMapClient = sqlMapClient;
    }
    
    public SqlMapClient getSqlMapClient() {
    	return sqlMapClient;
    }
    
    public Collection getKeys(String prefix, int type) throws PropertyException {
        if (prefix == null) {
            prefix = "";
        }

        SqlMapClient mapper = getSqlMapClient();
        try {
        	Map param = new HashMap();
        	param.put("prefix", prefix);
        	param.put("globalKey", globalKey);
        	if (type != 0) {
        		param.put("itemType", new Integer(type));
        	}
        	List list = mapper.queryForList("selectProperty", param);
        	ArrayList r = new ArrayList();
        	log.debug("list count: " + list.size());
        	
        	for (int i = 0; i < list.size(); i ++) {
        		PropertyData data = (PropertyData)list.get(i);
        		r.add(data.getItemKey());
        		log.debug("result item: " + data.getItemKey());
        	}
        	
        	return r;
        } catch (Exception e) {
            throw new PropertyException(e.getMessage());
        }
    }

    public int getType(String key) throws PropertyException {
    	SqlMapClient mapper = getSqlMapClient();
    	try {
    		Map param = new HashMap();
    		param.put("globalKey", globalKey);
    		param.put("itemKey", key);
    		PropertyData data = (PropertyData)mapper.queryForObject("selectProperty", param);
    		log.debug("query type: " + data.getItemType());
    		
    		return data.getItemType();
    	} catch (Exception e) {
    		throw new PropertyException(e.getMessage());
    	}
    }

    public boolean exists(String key) throws PropertyException {
        return getType(key) != 0;
    }

    public void init(Map config, Map args) {
        globalKey = (String) args.get("globalKey");
        setSqlMapClient((SqlMapClient) args.get("sqlMapClient"));
    }

    public void remove(String key) throws PropertyException {
    	SqlMapClient mapper = getSqlMapClient();
        try {
        	PropertyData data = new PropertyData();
        	data.setGlobalKey(globalKey);
        	data.setItemKey(key);
        	
        	int i = mapper.delete("deleteProperty", data);
        	log.debug("delete property key: " + data.getItemKey() + ", affected rows: " + i);
        } catch (Exception e) {
            throw new PropertyException(e.getMessage());
        }
    }

    protected void setImpl(int type, String key, Object value) throws PropertyException {
        if (value == null) {
            throw new PropertyException("IBatisPropertySet does not allow for null values to be stored");
        }

        SqlMapClient mapper = getSqlMapClient();
        try {
        	PropertyData data = new PropertyData();
        	data.setGlobalKey(globalKey);
        	data.setItemKey(key);
        	data.setItemType(type);
            setValues(data, type, key, value);

            log.debug("execute updata: updateProperty");
            int rows = mapper.update("updateProperty", data);
            log.debug("affected rows: " + rows);

            if (rows != 1) {
                // ok, this is a new value, insert it
                log.debug("execute insert insertProperty");
                mapper.insert("insertProperty", data);
                log.debug("inserted object");
            }
        } catch (Exception e) {
            throw new PropertyException(e.getMessage());
        }
    }

    protected Object get(int type, String key) throws PropertyException {
    	Object o = null;
    	SqlMapClient mapper = getSqlMapClient();
    	try {
    		Map param = new HashMap();
    		param.put("globalKey", globalKey);
    		param.put("itemKey", key);
    		PropertyData data = (PropertyData)mapper.queryForObject("selectProperty", param);
    		log.debug("result: " + data + ", type: " + data.getItemType());
    		
    		if (data.getItemType() != type) {
    			throw new InvalidPropertyTypeException();
    		}
    		
            switch (type) {
            case PropertySet.BOOLEAN:
                int boolVal = data.getNumberValue().intValue();
                o = new Boolean(boolVal == 1);
                break;
            case PropertySet.TEXT:
                o = data.getDataValue();;
                break;
            case PropertySet.DATE:
                o = data.getDateValue();
                break;
            case PropertySet.DOUBLE:
            	o = data.getFloatValue();
                break;
            case PropertySet.INT:
            	o = data.getNumberValue();
                break;
            case PropertySet.LONG:
            	o = data.getNumberValue();
                break;
            case PropertySet.STRING:
                o = data.getStringValue();
                break;
            default:
                throw new InvalidPropertyTypeException("IBatisPropertySet doesn't support this type yet.");
            }
    	} catch (Exception e) {
    		throw new PropertyException(e.getMessage());
    	}
    	log.debug("return object: " + o);
    	return o;
    }

    private void setValues(PropertyData data, int type, String key, Object value) throws PropertyException {
        switch (type) {
        case PropertySet.BOOLEAN:
            Boolean boolVal = (Boolean) value;
            data.setNumberValue(boolVal.booleanValue() ? java.math.BigDecimal.ONE : java.math.BigDecimal.ZERO);
            break;

        case PropertySet.TEXT:
            //Data dataa = (Data)value;
            data.setDataValue(value.toString());
            break;

        case PropertySet.DATE:
            Date date = (Date) value;
            data.setDateValue(date);
            break;

        case PropertySet.DOUBLE:
            Double d = (Double) value;
            data.setFloatValue(new Float(d.floatValue()));
            break;

        case PropertySet.INT:
            Integer i = (Integer) value;
            data.setNumberValue(java.math.BigDecimal.valueOf(i.floatValue()));
            break;

        case PropertySet.LONG:
            Long l = (Long) value;
            data.setNumberValue(java.math.BigDecimal.valueOf(l.floatValue()));
            break;

        case PropertySet.STRING:
        	data.setStringValue((String)value);
            break;

        default:
            throw new PropertyException("This type isn't supported!");
        }
    }
    
    /*
    private void closeConnection(Connection conn) {
        try {
            if ((conn != null) && !conn.isClosed()) {
                conn.commit();
            }
        } catch (SQLException e) {
            log.error("Could not commit connection");
        }
        try {
            if ((conn != null) && !conn.isClosed()) {
                conn.close();
            }
        } catch (SQLException e) {
            log.error("Could not close connection");
        }
    }
    */
}
